package com.ruoyi.web.easyExcel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.util.ConverterUtils;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.domain.excel.Total;
import com.ruoyi.web.mapper.TotalMapper;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.*;

@Slf4j
public class NoModelDataListener extends AnalysisEventListener<Map<Integer, String>> {
    TotalMapper totalMapper;
    /**
     * 每隔5条存储数据库，实际使用中可以100条，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    /**文件id*/
    private static  String FILE_ID = "";
    /**文件id**/
    private final String fileId;
    /**文件名**/
    private final String fileName;
    /**表头集合**/
    private List<List<String>> headList;
    /**数据数量**/
    private int n=0;
    /**合计项列号**/
    private int countFieldIndex;
    /**筛选条件列号**/
    private int numberFieldIndex;
    /**筛选条件**/
    private List<String> numbers;
    /**文件目录**/
    private String directoryOfFilted;
    /**筛选结果**/
    private Map<String,Map<String,String>> resultMap=new TreeMap<>();
    /**总计数**/
    final double[] t = {0};
    /**开始计时**/
    private static long before=System.currentTimeMillis();

    private List<Map<Integer, String>> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    public NoModelDataListener(String directoryOfFilted,String fileId,String fileName,List<String> numbers,TotalMapper totalMapper) {
        this.fileId=fileId;
        this.fileName=fileName;
        this.numbers = numbers;
        this.directoryOfFilted=directoryOfFilted;
        this.totalMapper=totalMapper;
    }

    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
        cachedDataList.add(data);
        if (cachedDataList.size() >= BATCH_COUNT) {
            log.info("解析到{}条数据", cachedDataList.size());
            saveData();
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        log.info("所有数据合计完成！共合计{}条数据,用时{}",n,(System.currentTimeMillis()-before)/1000);
        //计算总值并保存
        resultMap.forEach((k,v)->{
            QueryWrapper<Total> queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("account_number",k).eq("project_name",fileName.substring(0,fileName.lastIndexOf(".")));
            totalMapper.delete(queryWrapper);
            Total total=new Total();
            total.setTotal(Double.parseDouble(v.get("total")))
                    .setProjectName(fileName.substring(0,fileName.lastIndexOf(".")))
                    .setAccountNumber(k)
                            .setFileId(fileId);
            totalMapper.insert(total);
            t[0] = t[0] + Double.parseDouble(v.get("total"));
        });
        //若没有找到结算金额项
        if(countFieldIndex==0){
            n=0;
            t[0]=0;
        }
        Map<String,String> rMap=new HashMap<>();
        rMap.put("count",String.valueOf(n));
        rMap.put("total",String.valueOf(t[0]));
        resultMap.put("总计",rMap);
        log.info("计算总数为{},总值为{}",n, t[0]);
        //写入总计的表
        File file=new File(directoryOfFilted+fileName);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        File tempFile=new File(directoryOfFilted+"temp.xlsx");
        List<Map<Integer,String>> dataList=EasyExcel.read(file).sheet(0).doReadSync();
        try (ExcelWriter excelWriter = EasyExcel.write(tempFile).build()) {
            WriteSheet writeSheet0 = EasyExcel.writerSheet(0).sheetName("内容").head(headList).build();
            WriteSheet writeSheet1 = EasyExcel.writerSheet(1).sheetName("合计").head(head()).build();
            excelWriter.write(dataList, writeSheet0);
            excelWriter.write(dataList(), writeSheet1);
            excelWriter.finish();
        }

        if (tempFile.exists()){
            file.delete();
            if(countFieldIndex==0){
                file=new File(directoryOfFilted+"(未找到金额项)"+fileName);
            }
            tempFile.renameTo(file);
        }
    }

    /**
     * 这里会一行行的返回头
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
        log.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
        //解析到头数据并保存
        Map<Integer, String> headMap2=ConverterUtils.convertToStringMap(headMap, context);
        headList=new ArrayList<>();
        headMap2.forEach((k,v)->{
            List<String> head=new ArrayList<>();
            head.add(v);
            headList.add(head);
        });
        //找到计算项列号
        String[] countFieldArray={"结算金额","渠道星级积分补贴金额"};
        for (String s : countFieldArray) {
            if(headMap2.containsValue(s)){
                headMap2.forEach((k,v)->{
                    if(s.equals(v)&& StringUtils.isNotEmpty(v)){
                        countFieldIndex=k;
                    }
                });
                break;
            }
        }
        if(countFieldIndex==0){
            log.error("{},该文件找不到结算金额项",fileName);
        }
        //找到条件列号
        String[] numbersArray={"渠道编码","受理局向","渠道编号","代理商编码","渠道"};
        for (String s : numbersArray) {
            if(headMap2.containsValue(s)){
                headMap2.forEach((k,v)->{
                    if(s.equals(v)&& StringUtils.isNotEmpty(v)){
                        numberFieldIndex=k;
                    }
                });
            }
        }

    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        //计算总数据量
        n=n+cachedDataList.size();
        //计算总值

        //计算总值
        //遍历筛选条件
        for (String num : numbers) {
            Map<String,String> dataMap;
            int count=0;
            double total=0;
            if(resultMap.containsKey(num)){
                dataMap=resultMap.get(num);
                count=Integer.parseInt(dataMap.get("count"));
                total=Double.parseDouble(dataMap.get("total"));
            }else{
                dataMap=new HashMap<>(2);
                dataMap.put("count",String.valueOf(count));
                dataMap.put("total",String.valueOf(total));
            }
            //遍历数据
            for (Map<Integer, String> i : cachedDataList) {
                //找到筛选项并对比
                if(num.equals(i.get(numberFieldIndex))){
                    count++;
                    if(StringUtils.isNotNull(i.get(countFieldIndex))){
                        total=total+Double.parseDouble(i.get(countFieldIndex));
                    }
                    dataMap.put("total",String.valueOf(total));
                    dataMap.put("count",String.valueOf(count));
                }
            }
            resultMap.put(num,dataMap);
        }

    }

    /**
     * @Author GuoX
     * @Description 生成表头
     * @Date 2023/6/15 16:15
     * @Param
     * @return
     **/
    private List<List<String>> head() {
        List<List<String>> list = ListUtils.newArrayList();
        List<String> head0 = ListUtils.newArrayList();
        head0.add("渠道编码");
        List<String> head1 = ListUtils.newArrayList();
        head1.add("数量" );
        List<String> head2 = ListUtils.newArrayList();
        head2.add("合计" );
        list.add(head0);
        list.add(head1);
        list.add(head2);
        return list;
    }

    /***
     * @Author GuoX
     * @Description 生成表数据
     * @Date 2023/6/15 16:18
     * @Param []
     * @return java.util.List<java.util.List<java.lang.Object>>
     **/
    private List<List<Object>> dataList() {
        List<List<Object>> list = ListUtils.newArrayList();
        resultMap.forEach((k,v)->{
            List<Object> data=ListUtils.newArrayList();
            data.add(k);
            if (countFieldIndex == 0) {
               data.add("0");
               data.add("0");
            }else{
                data.add(v.get("count"));
                data.add(v.get("total"));
            }
            list.add(data);
        });
        return list;
    }


}
